# Copyright (c) 2019 Presto Labs Pte. Ltd.
# Author: jhkim

import collections
import math
# import itertools


def get_norm_pos(executor):
  centered_pos = 0 if executor._position is None else executor._position - executor.config2.reserve
  norm_pos = centered_pos / (executor.config.max_pos - executor.config.min_pos) * 2
  return norm_pos


def ceil_price(price, tick_size):
  return math.ceil(price / tick_size) * tick_size


def floor_price(price, tick_size):
  return math.floor(price / tick_size) * tick_size


def send_cancels(executor):
  if executor._cancel_executor.has_cancel():
    executor._traits._cancel_orders(executor._cancel_executor.get_cancel_list())
    print("try cancel on " + str(executor._cancel_executor.get_cancel_list()))
  executor._reset_action()


def get_best_order(executor, sign):
  if sign == 1:
    if len(executor._wo.buy_working_orders) > 0:
      among = [
          buy_order.price
          for buy_order in executor._wo.buy_working_orders
          if not buy_order.cancel_sent
      ]
      if len(among) == 0:
        return None
      return max(among)
  else:
    if len(executor._wo.sell_working_orders) > 0:
      among = [
          sell_order.price
          for sell_order in executor._wo.sell_working_orders
          if not sell_order.cancel_sent
      ]
      if len(among) == 0:
        return None
      return min(among)
    assert sign == -1, sign
  return None


class LmPassLogic(object):
  def __init__(self, *, config, trade_product, trade_pindex, logger):
    self._config = config
    self._logger = logger
    self._prev_manage_timestamp = 0
    self._trade_product = trade_product
    self._trade_pindex = trade_pindex
    self._lot_size = self._config['lot_size']
    self._post_threshold_bps = self._config.get('threshold_bps', None)
    self._cancel_threshold_bps = self._config.get('cancel_threshold_bps', None)
    self._taker_threshold_bps = self._config.get('taker_threshold_bps', None)
    self._lean_bps = self._config.get('lean_edge_bps', None)
    self._model_output_is_bps = self._config['model_output_is_bps']
    self._tick_size = self._config['tick_size']
    self._registered = {}
    self._bbo_list = []
    self._a0qsum = 0
    self._b0qsum = 0
    self._a0qmean = 0
    self._b0qmean = 0
    self._prev_long_pos = 0
    self._prev_short_pos = 0
    self._prev_force_fire_buy = 0
    self._prev_force_fire_sell = 0
    self._force_fire_cooldown = 200 * 1e6

  def update_pos_and_log(self, executor):
    if not hasattr(executor._og.og_info, 'get_product_position_proto'):
      return
    position = executor._og.og_info.get_product_position_proto(executor._product)
    short_pos = abs(position.short_position)
    long_pos = abs(position.long_position)
    if not math.isclose(short_pos, self._prev_short_pos):
      self._logger.info('Short position changed. %s -> %s' % (self._prev_short_pos, short_pos))
    if not math.isclose(long_pos, self._prev_long_pos):
      self._logger.info('Long position changed. %s -> %s' % (self._prev_long_pos, long_pos))
    self._prev_short_pos = short_pos
    self._prev_long_pos = long_pos

  def update_bbo_qty_ma(self, a0_qty, b0_qty, timestamp, window_size_in_sec=60):
    if len(self._bbo_list) > 0 and self._bbo_list[-1][2] + 500e6 > timestamp:
      return
    window_size = window_size_in_sec * 1e9
    self._a0qsum += a0_qty
    self._b0qsum += b0_qty
    self._bbo_list.append((a0_qty, b0_qty, timestamp))
    if self._bbo_list[0][2] + window_size < timestamp:
      for idx in range(len(self._bbo_list)):
        if self._bbo_list[idx][2] + window_size >= timestamp:
          self._bbo_list = self._bbo_list[idx:]
          break
        else:
          self._a0qsum -= self._bbo_list[idx][0]
          self._b0qsum -= self._bbo_list[idx][1]
    self._a0qmean = self._a0qsum / len(self._bbo_list)
    self._b0qmean = self._b0qsum / len(self._bbo_list)

  def get_bbo_queuenums(self, model, pindex, executor, bid0, ask0):
    queuedict = {1: None, -1: None}

    for wos, bbop, sign in [(executor._wo.buy_working_orders, bid0, 1),
                            (executor._wo.sell_working_orders, ask0, -1)]:
      for wo in wos:
        if math.isclose(bbop, wo.price):
          if wo.order_id not in self._registered:
            self._registered[wo.order_id] = model.RegisterOrder(pindex, wo.price, sign)
          queuedict[sign] = max(0, model.GetQueuePos(self._registered[wo.order_id]))
    return queuedict[-1], queuedict[1]

  def manage_orders(self, *, executor, timestamp):
    if executor is None:
      return
    if timestamp - self._prev_manage_timestamp > 20e6:
      executor.manage2_mm_orders()
    self._prev_manage_timestamp = timestamp

  def get_level_dict(self, cancel_models):
    level_dict = collections.defaultdict(list)
    for cancel_model in cancel_models:
      level_dict[cancel_model.level_info].append(cancel_model)
    return level_dict

  def get_signal_from_proto(self, signals_proto, queue_pos):
    if queue_pos is None:
      queue_pos = 1.0
    for signal_proto in signals_proto:
      if queue_pos <= signal_proto.queue_info:
        return signal_proto.signal
    return None

  def get_signal_from_dict(self, model_dict, price_dev):
    bp_list = sorted(list(model_dict.keys()))
    for bp in bp_list:
      if price_dev <= bp:
        return self.get_min_signal_from_proto(model_dict[bp])
    return None

  def get_bp_dict(self, models):
    bp_dict = collections.defaultdict(list)
    for model in models:
      bp_dict[model.bp_info].append(model)
    return bp_dict

  def get_min_signal_from_proto(self, signals_proto):
    return min([signal_proto.signal for signal_proto in signals_proto])

  def try_fire_and_manage(self, *, timestamp, executor, feed_converter, model, book, dry_run):
    self.try_fire_impl(timestamp=timestamp,
                       executor=executor,
                       feed_converter=feed_converter,
                       model=model,
                       book=book,
                       dry_run=dry_run)
    self.manage_orders(timestamp=timestamp, executor=executor)

  def get_taker_qty(self, executor, sign):
    if executor._position is None:
      return -1
    current_pos = executor._position - executor.config2.reserve
    if sign == 1:
      for order in executor._wo._buy_orders:
        current_pos += order.qty
      if current_pos >= 0:
        return -1
      return min(current_pos * -1, self._lot_size)
    elif sign == -1:
      for order in executor._wo._sell_orders:
        current_pos -= order.qty
      if current_pos <= 0:
        return -1
      return min(current_pos, self._lot_size)
    else:
      return -1

  def get_force_qty(self, executor, sign):
    if sign == 1:
      buy_potential = executor._position
      for order in executor._wo._buy_orders:
        buy_potential += order.qty
      return min(executor.config2.max_pos - buy_potential, self._lot_size)
    elif sign == -1:
      sell_potential = executor._position
      for order in executor._wo._sell_orders:
        sell_potential -= order.qty
      return min(sell_potential - executor.config2.min_pos, self._lot_size)
    else:
      return 0


class LmPassThickBookLogic(LmPassLogic):
  def __init__(self, *, config, trade_product, trade_pindex, logger):
    super().__init__(config=config,
                     trade_product=trade_product,
                     trade_pindex=trade_pindex,
                     logger=logger)
    assert self._model_output_is_bps
    self._range_max_ticks = self._config.get('range_max_ticks', self._config.get('range_limit', 0))
    self._edge_allowance_bps = self._config['edge_allowance_bps']

  def try_fire_impl(self, *, timestamp, executor, feed_converter, model, book, dry_run=None):
    if executor is None:
      return False

    if book is None:
      return False

    if not (book.has_ask() and book.has_bid()):
      return False

    self.update_pos_and_log(executor)

    ask0 = book.ask0().price
    bid0 = book.bid0().price
    sell_qty = self._lot_size
    buy_qty = self._lot_size

    buy_post_thres = self._post_threshold_bps
    sell_post_thres = self._post_threshold_bps
    buy_cancel_thres = self._cancel_threshold_bps
    sell_cancel_thres = self._cancel_threshold_bps
    buy_taker_thres = self._taker_threshold_bps
    sell_taker_thres = self._taker_threshold_bps

    if self._lean_bps > 0:
      norm_pos = get_norm_pos(executor)
      # norm pos can't exceed 1.0
      if norm_pos > 0:
        lean_edge = self._lean_bps * min(norm_pos, 1.0)
        buy_post_thres += lean_edge
        sell_post_thres -= lean_edge
        buy_taker_thres += lean_edge
        sell_taker_thres -= lean_edge
        # cancel = the higher threshold, the more frequent cancel
        buy_cancel_thres += lean_edge
        sell_cancel_thres -= lean_edge
      if norm_pos < 0:
        lean_edge = self._lean_bps * min(abs(norm_pos), 1.0)
        sell_post_thres += lean_edge
        buy_post_thres -= lean_edge
        sell_taker_thres += lean_edge
        buy_taker_thres -= lean_edge
        # cancel = the higher threshold, the more frequent cancel
        sell_cancel_thres += lean_edge
        buy_cancel_thres -= lean_edge

    ret_proto = model.Trigger(self._trade_pindex)

    buy_price = None
    sell_price = None

    cancel_buy_min_value = None
    cancel_sell_min_value = None

    bid_pq = book.get_bid_array(self._range_max_ticks + 1)
    ask_pq = book.get_ask_array(self._range_max_ticks + 1)

    buy_taker = False
    sell_taker = False

    if ret_proto is not None:
      buy_cancel_model = self.get_level_dict(ret_proto.bid_cancel_model)
      sell_cancel_model = self.get_level_dict(ret_proto.ask_cancel_model)

      if len(ret_proto.buy_model) > 0:
        for each_model in ret_proto.buy_model:
          if each_model.tag.find("sweep_to_mid") >= 0 and each_model.signal > buy_post_thres:
            buy_price = ask0 - self._tick_size
          if each_model.tag.find("agg_to_mid") >= 0 and each_model.signal > buy_taker_thres:
            buy_taker_qty = self.get_force_qty(executor, 1)
            if self._prev_force_fire_buy + self._force_fire_cooldown < timestamp \
               and buy_taker_qty > 0:
              buy_taker = True
              buy_taker_price = ask0 * (
                  1 + min(each_model.signal - buy_taker_thres, self._edge_allowance_bps) * 1e-4)
              buy_taker_price = floor_price(buy_taker_price, self._tick_size)
      if len(ret_proto.sell_model) > 0:
        for each_model in ret_proto.sell_model:
          if each_model.tag.find("sweep_to_mid") >= 0 and each_model.signal > sell_post_thres:
            sell_price = bid0 + self._tick_size
          if each_model.tag.find("agg_to_mid") >= 0 and each_model.signal > sell_taker_thres:
            sell_taker_qty = self.get_force_qty(executor, -1)
            if self._prev_force_fire_sell + self._force_fire_cooldown < timestamp \
               and sell_taker_qty > 0:
              sell_taker = True
              sell_taker_price = bid0 * (
                  1 - min(each_model.signal - sell_taker_thres, self._edge_allowance_bps) * 1e-4)
              sell_taker_price = ceil_price(sell_taker_price, self._tick_size)

      if not buy_taker and not sell_taker:
        if len(buy_cancel_model[0]) > 0:
          cancel_buy_min_value = self.get_min_signal_from_proto(buy_cancel_model[0])
        if len(sell_cancel_model[0]) > 0:
          cancel_sell_min_value = self.get_min_signal_from_proto(sell_cancel_model[0])
        executor._cancel_executor.cancel_buy_by_price(
            None, bid0 - self._tick_size * (self._range_max_ticks + 1))
        executor._cancel_executor.cancel_sell_by_price(
            None, ask0 + self._tick_size * (self._range_max_ticks + 1))
        send_cancels(executor)
        for wos, models, book_pq, sign in [(executor._wo._buy_orders, buy_cancel_model, bid_pq, 1),
                                           (executor._wo._sell_orders, sell_cancel_model, ask_pq,
                                            -1)]:
          for wo in wos:
            lev = None
            if sign == 1:
              for i, (bidp, _) in enumerate(book_pq):
                if wo.price >= bidp:
                  lev = i
                  break
            elif sign == -1:
              for i, (askp, _) in enumerate(book_pq):
                if wo.price <= askp:
                  lev = i
                  break
            if lev is not None and len(models[lev]) > 0:
              if wo.order_id not in self._registered:
                self._registered[wo.order_id] = model.RegisterOrder(self._trade_pindex,
                                                                    wo.price,
                                                                    sign)
              pos = max(0, model.GetQueuePos(self._registered[wo.order_id]))
              output = self.get_signal_from_proto(models[lev], pos)
              if sign == 1 and output < buy_cancel_thres:
                self._logger.info("cancel buy by signal, q=%s, signal=%s" % (pos, output))
                executor._cancel_executor.cancel_buy_by_price(wo.price, None)
                send_cancels(executor)
                self._last_bid_cancel_time = timestamp
              elif sign == -1 and output < sell_cancel_thres:
                self._logger.info("cancel sell by signal, q=%s, signal=%s" % (pos, output))
                executor._cancel_executor.cancel_sell_by_price(wo.price, None)
                send_cancels(executor)
                self._last_ask_cancel_time = timestamp
      else:
        executor._cancel_executor.cancel_buy_working_orders()
        executor._cancel_executor.cancel_sell_working_orders()
        send_cancels(executor)

    if buy_taker:
      executor.force_fire_buy_order(buy_price=buy_taker_price, buy_qty=buy_taker_qty)
      self._prev_force_fire_buy = timestamp
    if sell_taker:
      executor.force_fire_sell_order(sell_price=sell_taker_price, sell_qty=sell_taker_qty)
      self._prev_force_fire_sell = timestamp

    if not buy_taker and not sell_taker:
      if sell_price is not None or buy_price is not None:
        if sell_price is not None:
          sell_price = model.GetSweepPrice(self._trade_pindex, -1) or None
        if buy_price is not None:
          buy_price = model.GetSweepPrice(self._trade_pindex, 1) or None
        if sell_price is None or buy_price is None or buy_price < sell_price:
          executor.submit_mm_orders(sell_price=sell_price,
                                    buy_price=buy_price,
                                    sell_qty=sell_qty,
                                    buy_qty=buy_qty)
      elif cancel_buy_min_value is not None or cancel_sell_min_value is not None:
        if cancel_buy_min_value is not None and cancel_buy_min_value > buy_post_thres:
          buy_price = bid0
        if cancel_sell_min_value is not None and cancel_sell_min_value > sell_post_thres:
          sell_price = ask0
        if sell_price or buy_price:
          executor.submit_mm_orders(sell_price=sell_price,
                                    buy_price=buy_price,
                                    sell_qty=sell_qty,
                                    buy_qty=buy_qty)


class LmPassThinBookLogic(LmPassLogic):
  def __init__(self, *, config, trade_product, trade_pindex, logger):
    super().__init__(config=config,
                     trade_product=trade_product,
                     trade_pindex=trade_pindex,
                     logger=logger)
    assert self._model_output_is_bps
    self._range_max_bps = self._config.get('range_max_bps', self._config.get('range_limit', 10))
    self._edge_allowance_bps = self._config['edge_allowance_bps']

  def try_fire_impl(self, *, timestamp, executor, feed_converter, model, book, dry_run=None):
    if executor is None:
      return False

    if book is None:
      return False

    if not (book.has_ask() and book.has_bid()):
      return False

    self.update_pos_and_log(executor)

    ask0 = book.ask0().price
    bid0 = book.bid0().price
    sell_qty = self._lot_size
    buy_qty = self._lot_size

    buy_post_thres = self._post_threshold_bps
    sell_post_thres = self._post_threshold_bps
    buy_cancel_thres = self._cancel_threshold_bps
    sell_cancel_thres = self._cancel_threshold_bps
    buy_taker_thres = self._taker_threshold_bps
    sell_taker_thres = self._taker_threshold_bps

    if self._lean_bps > 0:
      norm_pos = get_norm_pos(executor)
      # norm pos can't exceed 1.0
      if norm_pos > 0:
        lean_edge = self._lean_bps * min(norm_pos, 1.0)
        buy_post_thres += lean_edge
        sell_post_thres -= lean_edge
        buy_taker_thres += lean_edge
        sell_taker_thres -= lean_edge
        # cancel = the higher threshold, the more frequent cancel
        buy_cancel_thres += lean_edge
        sell_cancel_thres -= lean_edge
      if norm_pos < 0:
        lean_edge = self._lean_bps * min(abs(norm_pos), 1.0)
        sell_post_thres += lean_edge
        buy_post_thres -= lean_edge
        sell_taker_thres += lean_edge
        buy_taker_thres -= lean_edge
        # cancel = the higher threshold, the more frequent cancel
        sell_cancel_thres += lean_edge
        buy_cancel_thres -= lean_edge

    ret_proto = model.Trigger(self._trade_pindex)

    buy_price = None
    sell_price = None

    buy_taker = False
    sell_taker = False

    if ret_proto is not None:
      buy_model = self.get_bp_dict(ret_proto.bid_cancel_model)
      sell_model = self.get_bp_dict(ret_proto.ask_cancel_model)
      buy_bp = sorted(list(buy_model.keys()))
      sell_bp = sorted(list(sell_model.keys()))

      if len(ret_proto.buy_model) > 0:
        buy_taker_qty = self.get_force_qty(executor, 1)
        if ret_proto.buy_model[0].signal > buy_taker_thres and \
           self._prev_force_fire_buy + self._force_fire_cooldown < timestamp and buy_taker_qty > 0:
          buy_taker = True
          buy_taker_price = ask0 * (1 + min(ret_proto.buy_model[0].signal - buy_taker_thres,
                                            self._edge_allowance_bps) * 1e-4)
          buy_taker_price = floor_price(buy_taker_price, self._tick_size)
      if len(ret_proto.sell_model) > 0:
        sell_taker_qty = self.get_force_qty(executor, -1)
        if ret_proto.sell_model[0].signal > sell_taker_thres and \
           self._prev_force_fire_sell + self._force_fire_cooldown < timestamp and \
           sell_taker_qty > 0:
          sell_taker = True
          sell_taker_price = bid0 * (1 - min(ret_proto.sell_model[0].signal - sell_taker_thres,
                                             self._edge_allowance_bps) * 1e-4)
          sell_taker_price = ceil_price(sell_taker_price, self._tick_size)

      if not buy_taker and not sell_taker:
        executor._cancel_executor.cancel_buy_by_price(
            None,
            floor_price((1 - self._range_max_bps * 1e-4) * bid0, self._tick_size) - self._tick_size)
        executor._cancel_executor.cancel_sell_by_price(
            None,
            ceil_price((1 + self._range_max_bps * 1e-4) * ask0, self._tick_size) + self._tick_size)
        send_cancels(executor)
        for wos, models, sign in [(executor._wo._buy_orders, buy_model, 1),
                                  (executor._wo._sell_orders, sell_model, -1)]:
          for wo in wos:
            if sign == 1:
              price_dev = (bid0 - wo.price) / bid0 * 1e4
              output = self.get_signal_from_dict(models, price_dev)
              if output is not None and output < buy_cancel_thres:
                executor._cancel_executor.cancel_buy_by_price(wo.price, None)
                send_cancels(executor)
                self._last_bid_cancel_time = timestamp
            elif sign == -1:
              price_dev = (wo.price - ask0) / ask0 * 1e4
              output = self.get_signal_from_dict(models, price_dev)
              if output is not None and output < sell_cancel_thres:
                executor._cancel_executor.cancel_sell_by_price(wo.price, None)
                send_cancels(executor)
                self._last_ask_cancel_time = timestamp
      else:
        executor._cancel_executor.cancel_buy_working_orders()
        executor._cancel_executor.cancel_sell_working_orders()
        send_cancels(executor)

      if buy_taker:
        executor.force_fire_buy_order(buy_price=buy_taker_price, buy_qty=buy_taker_qty)
        self._prev_force_fire_buy = timestamp
      if sell_taker:
        executor.force_fire_sell_order(sell_price=sell_taker_price, sell_qty=sell_taker_qty)
        self._prev_force_fire_sell = timestamp
      if not buy_taker and not sell_taker:
        for bp in buy_bp:
          if self.get_min_signal_from_proto(buy_model[bp]) > buy_post_thres:
            buy_price = floor_price((1 - bp * 1e-4) * bid0, self._tick_size)
            break
        for bp in sell_bp:
          if self.get_min_signal_from_proto(sell_model[bp]) > sell_post_thres:
            sell_price = ceil_price((1 + bp * 1e-4) * ask0, self._tick_size)
            break
        if sell_price is not None or buy_price is not None:
          executor.submit_mm_orders(sell_price=sell_price,
                                    buy_price=buy_price,
                                    sell_qty=sell_qty,
                                    buy_qty=buy_qty)


from coin.strategy.executor.passive.passive_executor import _in_bp


class LmPassPricerLogic(LmPassLogic):
  def __init__(self, *, config, trade_product, trade_pindex, logger):
    super().__init__(config=config,
                     trade_product=trade_product,
                     trade_pindex=trade_pindex,
                     logger=logger)
    assert self._model_output_is_bps
    self.edge = config['edge_info']['edge']
    self.edge_multiplier = config['edge_info']['edge_multiplier']
    self.agg_threshold = config['edge_info']['agg_threshold']
    self.is_bbo_edge = config['edge_info'].get('is_bbo_edge', True)

  def try_fire_impl(self, *, timestamp, executor, feed_converter, model, book, dry_run=None):
    if executor is None:
      return False

    if book is None:
      return False

    if not (book.has_ask() and book.has_bid()):
      return False

    ask0 = book.ask0().price
    bid0 = book.bid0().price

    if self.is_bbo_edge:
      buy_base_price = bid0
      sell_base_price = ask0
    else:
      midp = 0.5 * (ask0 + bid0)
      buy_base_price = midp * (1 - 1e-8)
      sell_base_price = midp * (1 + 1e-8)

    ret_proto = model.Trigger(self._trade_pindex)

    buy_price = None
    sell_price = None

    if ret_proto is not None:
      buy_signal = ret_proto.buy_edge_model[0].signal
      sell_signal = ret_proto.sell_edge_model[0].signal

      if len(ret_proto.buy_model) > 0:
        buy_agg_signal = ret_proto.buy_model[0].signal
        force_buy_qty = self.get_force_qty(executor, 1)
      else:
        buy_agg_signal = None

      if len(ret_proto.sell_model) > 0:
        sell_agg_signal = ret_proto.sell_model[0].signal
        force_sell_qty = self.get_force_qty(executor, -1)
      else:
        sell_agg_signal = None

      fire_agg = False
      if buy_agg_signal is not None and buy_agg_signal > self.agg_threshold and \
         self._prev_force_fire_buy + self._force_fire_cooldown < timestamp and \
         force_buy_qty >= self._lot_size:
        agg_buy_price_float = ask0 * (1 + min(buy_agg_signal - self.agg_threshold, 1.0) * 1e-4)
        agg_buy_price = floor_price(agg_buy_price_float, self._tick_size)
        executor.force_fire_buy_order(agg_buy_price, force_buy_qty)
        fire_agg = True
        self._prev_force_fire_buy = timestamp

      if sell_agg_signal is not None and sell_agg_signal > self.agg_threshold and \
         self._prev_force_fire_sell + self._force_fire_cooldown < timestamp and \
         force_sell_qty >= self._lot_size:
        agg_sell_price_float = bid0 * (1 - min(sell_agg_signal - self.agg_threshold, 1.0) * 1e-4)
        agg_sell_price = floor_price(agg_sell_price_float, self._tick_size)
        executor.force_fire_sell_order(agg_sell_price, force_sell_qty)
        fire_agg = True
        self._prev_force_fire_sell = timestamp

      buy_edge_neg = buy_signal * self.edge_multiplier + self.edge
      sell_edge_neg = sell_signal * self.edge_multiplier + self.edge

      buy_edge_neg = min(buy_edge_neg, 0)
      sell_edge_neg = min(sell_edge_neg, 0)

      sell_price = ceil_price((1 - sell_edge_neg * 1e-4) * sell_base_price, self._tick_size)
      buy_price = floor_price((1 + buy_edge_neg * 1e-4) * buy_base_price, self._tick_size)

      need_repost_side = {-1: True, 1: True}

      sticky_bp = executor.config.sticky_bp or 0

      cancels = {-1: [], 1: []}

      for orders, target_price, sign in [(executor._wo.buy_working_orders, buy_price, 1),
                                         (executor._wo.sell_working_orders, sell_price, -1)]:
        for order in orders:
          if not _in_bp(order.price, target_price, sticky_bp) and \
             not order.cancel_sent:
            cancels[sign].append(order.order_id)
            # need_cancel_side[sign] = True
          if _in_bp(order.price, target_price, sticky_bp) and \
             not order.cancel_sent:
            need_repost_side[sign] = False

      if not need_repost_side[1]:
        buy_price = None

      if not need_repost_side[-1]:
        sell_price = None

      executor._traits._cancel_orders(cancels[-1] + cancels[1])

      if fire_agg:
        executor.manage_mm_orders(
            sell_price=None,
            buy_price=None,  # cancel_all_existing_sell=True,
            # cancel_all_existing_buy=True)
        )
      else:
        # td = timestamp - self.prev_ts if hasattr(self, 'prev_ts') else 0
        # self.prev_ts = timestamp
        executor.manage_mm_orders(
            sell_price=sell_price,
            buy_price=buy_price,
            # cancel_all_existing_sell=need_cancel_side[-1],
            # cancel_all_existing_buy=need_cancel_side[1])
        )
